/**
 * Represents a route from one tile to another.
 */
public class Route implements Comparable<Route> {

	public enum RouteType {
		/**
		 * A complete route that has visibility from source to target.
		 */
		COMPLETE,

		/**
		 * An incomplete route that has some tile invisible from source to
		 * target.
		 */
		INCOMPLETE,

		/**
		 * A route that does not perform A* path finding which the distance is
		 * purely based on heuristic and the direction based on estimation.
		 */
		HEURISTIC,
	};

	private final Tile start;
	private final Tile end;
	private RouteType type;
	private final Aim direction;
	private final int distance;
	private final Tile firstUnexploredTile;

	public Route(Tile start, Tile end, RouteType type, Aim direction,
			int distance) {
		this(start, end, type, direction, distance, null);
	}

	public Route(Tile start, Tile end, RouteType type, Aim direction,
			int distance, Tile firstUnexploredTile) {
		this.start = start;
		this.end = end;
		this.type = type;
		this.direction = direction;
		this.distance = distance;
		this.firstUnexploredTile = firstUnexploredTile;
	}

	public boolean isCompleted() {
		return type == RouteType.COMPLETE;
	}

	public Tile getUnexplored() {
		return this.firstUnexploredTile;
	}

	public Tile getStart() {
		return start;
	}

	public Tile getEnd() {
		return end;
	}

	public int getDistance() {
		return distance;
	}

	public Aim getNext() {
		return direction;
	}

	@Override
	public int compareTo(Route route) {
		return distance - route.distance;
	}

	@Override
	public int hashCode() {
		return start.hashCode() * Ants.MAX_MAP_SIZE * Ants.MAX_MAP_SIZE
				+ end.hashCode();
	}

	@Override
	public boolean equals(Object o) {
		boolean result = false;
		if (o instanceof Route) {
			Route route = (Route) o;
			result = start.equals(route.start) && end.equals(route.end);
		}
		return result;
	}

	@Override
	public String toString() {
		if (this.type == RouteType.INCOMPLETE) {
			return String.format("%s: %s -> %s : %s : %d : %s ", this.type,
					this.start, this.end, this.direction, this.distance, this.firstUnexploredTile);
		} else {
			return String.format("%s: %s -> %s : %s : %d", this.type,
					this.start, this.end, this.direction, this.distance);
		}
	}
}